{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\bww\\AppData\\Local\\Temp\\ipykernel_1936\\560657783.py:2: DeprecationWarning: \n",
      "Pyarrow will become a required dependency of pandas in the next major release of pandas (pandas 3.0),\n",
      "(to allow more performant data types, such as the Arrow string type, and better interoperability with other libraries)\n",
      "but was not found to be installed on your system.\n",
      "If this would cause problems for you,\n",
      "please provide us feedback at https://github.com/pandas-dev/pandas/issues/54466\n",
      "        \n",
      "  import pandas as pd\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import pybroker\n",
    "from numba import njit\n",
    "from pybroker import Strategy, StrategyConfig, YFinance\n",
    "from pybroker.ext.data import AKShare"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 将训练过的模型缓存到磁盘\n",
    "pybroker.enable_caches('walkforward_strategy')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 计算收盘价减去移动平均价（CMMA）的指标。以下是 CMMA 指标的代码：\n",
    "def cmma(bar_data, lookback):\n",
    "\n",
    "    @njit  # Enable Numba JIT.\n",
    "    def vec_cmma(values):\n",
    "        # Initialize the result array.\n",
    "        n = len(values)\n",
    "        out = np.array([np.nan for _ in range(n)])\n",
    "\n",
    "        # For all bars starting at lookback:\n",
    "        for i in range(lookback, n):\n",
    "            # Calculate the moving average for the lookback.\n",
    "            ma = 0\n",
    "            for j in range(i - lookback, i):\n",
    "                ma += values[j]\n",
    "            ma /= lookback\n",
    "            # Subtract the moving average from value.\n",
    "            out[i] = values[i] - ma\n",
    "        return out\n",
    "\n",
    "    # Calculate for close prices.\n",
    "    return vec_cmma(bar_data.close)\n",
    "\n",
    "cmma_20 = pybroker.indicator('cmma_20', cmma, lookback=20)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 训练和回测\n",
    "构建一个模型，使用 20 天的 CMMA 预测第二天的回报。使用 简单线性回归 是开始实验的好方法。下面我们从 scikit-learn 导入一个 LinearRegression 模型："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.linear_model import LinearRegression\n",
    "from sklearn.metrics import r2_score"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 我们创建一个 train_slr 函数来训练 LinearRegression 模型：\n",
    "'''\n",
    "输入参数:\n",
    "symbol: 股票或其他金融证券的标识符（尽管在此函数中未直接使用）。\n",
    "train_data: 用于训练模型的DataFrame，包含 'close' 和 'cmma_20' 列。\n",
    "test_data: 用于测试模型的DataFrame，同样包含 'close' 和 'cmma_20' 列。\n",
    "'''\n",
    "def train_slr(symbol, train_data, test_data):\n",
    "    # Train 训练部分:\n",
    "    # Previous day close prices.    计算前一天的收盘价 train_prev_close。\n",
    "    train_prev_close = train_data['close'].shift(1)\n",
    "    # Calculate daily returns.  计算每日回报率 train_daily_returns。\n",
    "    train_daily_returns = (train_data['close'] - train_prev_close) / train_prev_close\n",
    "    # Predict next day's return.    预测次日的回报率，并将其存储为 'pred' 列。\n",
    "    # 在实际使用中，由于 'pred' 列是基于未来数据（次日回报率）的，所以在实际预测时是不可用的。\n",
    "    # 这里只是为了评估模型性能而使用的回溯测试。\n",
    "    # 这里其实是在使用次日实际的回报率作为目标值，这在现实中是未知的，但在回溯测试中是可行的。\n",
    "    train_data['pred'] = train_daily_returns.shift(-1)\n",
    "    train_data = train_data.dropna()    #删除包含 NaN 值的行（因为 shift 操作会在开始处引入缺失值）。\n",
    "    # Train the LinearRegession model to predict the next day's return\n",
    "    # 使用 'cmma_20' 作为特征（X），次日预测的回报率作为目标（y），训练线性回归模型。\n",
    "    # given the 20-day CMMA.\n",
    "    X_train = train_data[['cmma_20']]\n",
    "    y_train = train_data[['pred']]\n",
    "    model = LinearRegression()\n",
    "    model.fit(X_train, y_train)\n",
    "\n",
    "    # Test  测试部分\n",
    "    # 对测试集执行与训练集相同的预处理步骤。\n",
    "    test_prev_close = test_data['close'].shift(1)\n",
    "    test_daily_returns = (test_data['close'] - test_prev_close) / test_prev_close\n",
    "    test_data['pred'] = test_daily_returns.shift(-1)\n",
    "    test_data = test_data.dropna()\n",
    "    X_test = test_data[['cmma_20']]\n",
    "    y_test = test_data[['pred']]\n",
    "    # Make predictions from test data.  使用训练好的模型对测试集进行预测。\n",
    "    y_pred = model.predict(X_test)\n",
    "    # Print goodness of fit.    使用 r2_score 计算模型在测试集上的决定系数（R^2），并打印出来。\n",
    "    r2 = r2_score(y_test, np.squeeze(y_pred))\n",
    "    print(symbol, f'R^2={r2}')\n",
    "\n",
    "    # Return the trained model and columns to use as input data.\n",
    "    # 返回值:返回训练好的模型以及用于输入数据的列名列表（在此例中为 ['cmma_20']）。\n",
    "    return model, ['cmma_20']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "train_slr 函数使用 20 天的 CMMA 作为 LinearRegression 模型的输入特征或预测因子。然后，该函数将 LinearRegression 模型拟合到该股票代码的训练数据。\n",
    "\n",
    "拟合模型后，该函数使用测试数据评估模型的准确性，具体地说，是通过计算 R 平方 得分。R 平方得分提供了一个衡量 LinearRegression 模型拟合测试数据有多好的方法。\n",
    "\n",
    "train_slr 函数的最终输出是针对该股票代码的训练过的 LinearRegression 模型，以及用作预测输入数据的 cmma_20 列。回测过程中，PyBroker 将使用此模型预测股票的第二天回报。对于每个股票代码，都会调用 train_slr 函数，训练过的模型将用于预测每个股票的第二天回报。\n",
    "\n",
    "定义了训练模型的函数之后，需要将其注册到 PyBroker。这是通过使用 pybroker.model 函数创建一个新的 ModelSource 实例来完成的。此函数的参数是模型的名称（在本例中为 'slr'）、将训练模型的函数（train_slr）以及作为模型输入的指标列表（在本例中为 cmma_20）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "model_slr = pybroker.model('slr', train_slr, indicators=[cmma_20])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "config = StrategyConfig(bootstrap_sample_size=100)\n",
    "strategy = Strategy(AKShare(), '3/1/2017', '3/1/2022', config)\n",
    "#  Strategy 对象上调用 add_execution 方法来指定交易执行的详细信息。\n",
    "# 将 None 值作为第一个参数传递，这意味着在回测期间不会使用交易功能。\n",
    "strategy.add_execution(None, ['000001', '000002'], models=model_slr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Backtesting: 2017-03-01 00:00:00 to 2022-03-01 00:00:00\n",
      "\n",
      "Loading bar data...\n",
      "Loaded bar data: 0:00:01 \n",
      "\n",
      "Computing indicators...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "  0% (0 of 2) |                          | Elapsed Time: 0:00:00 ETA:  --:--:--\n",
      " 50% (1 of 2) |#############             | Elapsed Time: 0:00:08 ETA:   0:00:08\n",
      "100% (2 of 2) |##########################| Elapsed Time: 0:00:08 Time:  0:00:08\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Train split: 2017-03-01 00:00:00 to 2019-08-22 00:00:00\n",
      "000001 R^2=0.00031352596899358876\n",
      "000002 R^2=-0.0008275279942651093\n",
      "Finished training models: 0:00:00 \n",
      "\n",
      "Finished backtest: 0:00:09\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "TestResult(start_date=datetime.datetime(2017, 3, 1, 0, 0), end_date=datetime.datetime(2022, 3, 1, 0, 0), portfolio=Empty DataFrame\n",
       "Columns: []\n",
       "Index: [], positions=Empty DataFrame\n",
       "Columns: []\n",
       "Index: [], orders=Empty DataFrame\n",
       "Columns: []\n",
       "Index: [], trades=Empty DataFrame\n",
       "Columns: []\n",
       "Index: [], metrics=EvalMetrics(trade_count=0, initial_market_value=0, end_market_value=0, total_pnl=0, unrealized_pnl=0, total_return_pct=0, annual_return_pct=None, total_profit=0, total_loss=0, total_fees=0, max_drawdown=0, max_drawdown_pct=0, win_rate=0, loss_rate=0, winning_trades=0, losing_trades=0, avg_pnl=0, avg_return_pct=0, avg_trade_bars=0, avg_profit=0, avg_profit_pct=0, avg_winning_trade_bars=0, avg_loss=0, avg_loss_pct=0, avg_losing_trade_bars=0, largest_win=0, largest_win_pct=0, largest_win_bars=0, largest_loss=0, largest_loss_pct=0, largest_loss_bars=0, max_wins=0, max_losses=0, sharpe=0, sortino=0, calmar=None, profit_factor=0, ulcer_index=0, upi=0, equity_r2=0, std_error=0, annual_std_error=None, annual_volatility_pct=None), metrics_df=Empty DataFrame\n",
       "Columns: []\n",
       "Index: [], bootstrap=None, signals=None, stops=None)"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 调用 backtest 方法进行回测，设置 train_size 为 0.5 以指定模型应该在回测数据的前半部分进行训练，并在后半部分进行测试。\n",
    "strategy.backtest(train_size=0.5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 向前分析"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def hold_long(ctx):\n",
    "    if not ctx.long_pos():\n",
    "        # Buy if the next bar is predicted to have a positive return:\n",
    "        if ctx.preds('slr')[-1] > 0:\n",
    "            ctx.buy_shares = 100\n",
    "    else:\n",
    "        # Sell if the next bar is predicted to have a negative return:\n",
    "        if ctx.preds('slr')[-1] < 0:\n",
    "            ctx.sell_shares = 100\n",
    "\n",
    "strategy.clear_executions()\n",
    "strategy.add_execution(hold_long, ['000001', '000002'], models=model_slr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Backtesting: 2017-03-01 00:00:00 to 2022-03-01 00:00:00\n",
      "\n",
      "Loaded cached bar data.\n",
      "\n",
      "Loaded cached indicator data.\n",
      "\n",
      "Train split: 2017-03-08 00:00:00 to 2018-06-01 00:00:00\n",
      "000001 R^2=-0.0010114027668275405\n",
      "000002 R^2=-0.003575781617444429\n",
      "Finished training models: 0:00:00 \n",
      "\n",
      "Test split: 2018-06-04 00:00:00 to 2019-08-27 00:00:00\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "  0% (0 of 303) |                        | Elapsed Time: 0:00:00 ETA:  --:--:--\n",
      "  6% (21 of 303) |#                      | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 10% (31 of 303) |##                     | Elapsed Time: 0:00:00 ETA:   0:00:01\n",
      " 16% (51 of 303) |###                    | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 20% (61 of 303) |####                   | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 26% (81 of 303) |######                 | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 33% (101 of 303) |#######               | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 39% (121 of 303) |########              | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 43% (131 of 303) |#########             | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 49% (151 of 303) |##########            | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 53% (161 of 303) |###########           | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 59% (181 of 303) |#############         | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 69% (211 of 303) |###############       | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 76% (231 of 303) |################      | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 82% (251 of 303) |##################    | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 89% (271 of 303) |###################   | Elapsed Time: 0:00:01 ETA:   0:00:00\n",
      " 92% (281 of 303) |####################  | Elapsed Time: 0:00:01 ETA:   0:00:00\n",
      " 96% (291 of 303) |##################### | Elapsed Time: 0:00:01 ETA:   0:00:00\n",
      "100% (303 of 303) |######################| Elapsed Time: 0:00:01 Time:  0:00:01\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Train split: 2018-06-04 00:00:00 to 2019-08-27 00:00:00\n",
      "000001 R^2=-0.0005142407824130224\n",
      "000002 R^2=0.0015659999276117498\n",
      "Finished training models: 0:00:00 \n",
      "\n",
      "Test split: 2019-08-28 00:00:00 to 2020-11-27 00:00:00\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "  0% (0 of 303) |                        | Elapsed Time: 0:00:00 ETA:  --:--:--\n",
      "  3% (11 of 303) |                       | Elapsed Time: 0:00:00 ETA:   0:00:02\n",
      "  6% (21 of 303) |#                      | Elapsed Time: 0:00:00 ETA:   0:00:02\n",
      " 13% (41 of 303) |###                    | Elapsed Time: 0:00:00 ETA:   0:00:01\n",
      " 16% (51 of 303) |###                    | Elapsed Time: 0:00:00 ETA:   0:00:01\n",
      " 23% (71 of 303) |#####                  | Elapsed Time: 0:00:00 ETA:   0:00:01\n",
      " 33% (101 of 303) |#######               | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 36% (111 of 303) |########              | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 43% (131 of 303) |#########             | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 46% (141 of 303) |##########            | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 49% (151 of 303) |##########            | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 53% (161 of 303) |###########           | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 56% (171 of 303) |############          | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 63% (191 of 303) |#############         | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 69% (211 of 303) |###############       | Elapsed Time: 0:00:01 ETA:   0:00:00\n",
      " 72% (221 of 303) |################      | Elapsed Time: 0:00:01 ETA:   0:00:00\n",
      " 76% (231 of 303) |################      | Elapsed Time: 0:00:01 ETA:   0:00:00\n",
      " 82% (251 of 303) |##################    | Elapsed Time: 0:00:01 ETA:   0:00:00\n",
      " 89% (271 of 303) |###################   | Elapsed Time: 0:00:01 ETA:   0:00:00\n",
      " 96% (291 of 303) |##################### | Elapsed Time: 0:00:01 ETA:   0:00:00\n",
      " 99% (301 of 303) |##################### | Elapsed Time: 0:00:01 ETA:   0:00:00\n",
      "100% (303 of 303) |######################| Elapsed Time: 0:00:01 Time:  0:00:01\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Train split: 2019-08-28 00:00:00 to 2020-11-27 00:00:00\n",
      "000001 R^2=-0.003959027558596784\n",
      "000002 R^2=-0.004194638912290882\n",
      "Finished training models: 0:00:00 \n",
      "\n",
      "Test split: 2020-11-30 00:00:00 to 2022-03-01 00:00:00\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "  0% (0 of 303) |                        | Elapsed Time: 0:00:00 ETA:  --:--:--\n",
      "  6% (21 of 303) |#                      | Elapsed Time: 0:00:00 ETA:   0:00:01\n",
      " 13% (41 of 303) |###                    | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 20% (61 of 303) |####                   | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 26% (81 of 303) |######                 | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 33% (101 of 303) |#######               | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 36% (111 of 303) |########              | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 39% (121 of 303) |########              | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 46% (141 of 303) |##########            | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 53% (161 of 303) |###########           | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 59% (181 of 303) |#############         | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 66% (201 of 303) |##############        | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 76% (231 of 303) |################      | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 82% (251 of 303) |##################    | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 89% (271 of 303) |###################   | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 96% (291 of 303) |##################### | Elapsed Time: 0:00:01 ETA:   0:00:00\n",
      "100% (303 of 303) |######################| Elapsed Time: 0:00:01 Time:  0:00:01\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Calculating bootstrap metrics: sample_size=100, samples=10000...\n",
      "Calculated bootstrap metrics: 0:00:09 \n",
      "\n",
      "Finished backtest: 0:00:19\n"
     ]
    }
   ],
   "source": [
    "result = strategy.walkforward(\n",
    "    warmup=20,\n",
    "    windows=3,\n",
    "    train_size=0.5,\n",
    "    lookahead=1,\n",
    "    calc_bootstrap=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>name</th>\n",
       "      <th>value</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>trade_count</td>\n",
       "      <td>42.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>initial_market_value</td>\n",
       "      <td>100000.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>end_market_value</td>\n",
       "      <td>101667.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>total_pnl</td>\n",
       "      <td>2778.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>unrealized_pnl</td>\n",
       "      <td>-1111.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>total_return_pct</td>\n",
       "      <td>2.778000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>total_profit</td>\n",
       "      <td>4190.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>total_loss</td>\n",
       "      <td>-1412.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>total_fees</td>\n",
       "      <td>0.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>max_drawdown</td>\n",
       "      <td>-1538.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>max_drawdown_pct</td>\n",
       "      <td>-1.493479</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>win_rate</td>\n",
       "      <td>78.571429</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>loss_rate</td>\n",
       "      <td>21.428571</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>winning_trades</td>\n",
       "      <td>33.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>losing_trades</td>\n",
       "      <td>9.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>avg_pnl</td>\n",
       "      <td>66.142857</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>16</th>\n",
       "      <td>avg_return_pct</td>\n",
       "      <td>4.580000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>17</th>\n",
       "      <td>avg_trade_bars</td>\n",
       "      <td>29.952381</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>18</th>\n",
       "      <td>avg_profit</td>\n",
       "      <td>126.969697</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19</th>\n",
       "      <td>avg_profit_pct</td>\n",
       "      <td>7.346364</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>20</th>\n",
       "      <td>avg_winning_trade_bars</td>\n",
       "      <td>26.696970</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>21</th>\n",
       "      <td>avg_loss</td>\n",
       "      <td>-156.888889</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>22</th>\n",
       "      <td>avg_loss_pct</td>\n",
       "      <td>-5.563333</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>23</th>\n",
       "      <td>avg_losing_trade_bars</td>\n",
       "      <td>41.888889</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>24</th>\n",
       "      <td>largest_win</td>\n",
       "      <td>759.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25</th>\n",
       "      <td>largest_win_pct</td>\n",
       "      <td>87.440000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>26</th>\n",
       "      <td>largest_win_bars</td>\n",
       "      <td>306.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>27</th>\n",
       "      <td>largest_loss</td>\n",
       "      <td>-834.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>28</th>\n",
       "      <td>largest_loss_pct</td>\n",
       "      <td>-26.650000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>29</th>\n",
       "      <td>largest_loss_bars</td>\n",
       "      <td>98.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>30</th>\n",
       "      <td>max_wins</td>\n",
       "      <td>9.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>31</th>\n",
       "      <td>max_losses</td>\n",
       "      <td>1.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>32</th>\n",
       "      <td>sharpe</td>\n",
       "      <td>0.025750</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>33</th>\n",
       "      <td>sortino</td>\n",
       "      <td>0.036708</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>34</th>\n",
       "      <td>profit_factor</td>\n",
       "      <td>1.075849</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>35</th>\n",
       "      <td>ulcer_index</td>\n",
       "      <td>0.206049</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>36</th>\n",
       "      <td>upi</td>\n",
       "      <td>0.008957</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37</th>\n",
       "      <td>equity_r2</td>\n",
       "      <td>0.713317</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>38</th>\n",
       "      <td>std_error</td>\n",
       "      <td>798.998923</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                      name          value\n",
       "0              trade_count      42.000000\n",
       "1     initial_market_value  100000.000000\n",
       "2         end_market_value  101667.000000\n",
       "3                total_pnl    2778.000000\n",
       "4           unrealized_pnl   -1111.000000\n",
       "5         total_return_pct       2.778000\n",
       "6             total_profit    4190.000000\n",
       "7               total_loss   -1412.000000\n",
       "8               total_fees       0.000000\n",
       "9             max_drawdown   -1538.000000\n",
       "10        max_drawdown_pct      -1.493479\n",
       "11                win_rate      78.571429\n",
       "12               loss_rate      21.428571\n",
       "13          winning_trades      33.000000\n",
       "14           losing_trades       9.000000\n",
       "15                 avg_pnl      66.142857\n",
       "16          avg_return_pct       4.580000\n",
       "17          avg_trade_bars      29.952381\n",
       "18              avg_profit     126.969697\n",
       "19          avg_profit_pct       7.346364\n",
       "20  avg_winning_trade_bars      26.696970\n",
       "21                avg_loss    -156.888889\n",
       "22            avg_loss_pct      -5.563333\n",
       "23   avg_losing_trade_bars      41.888889\n",
       "24             largest_win     759.000000\n",
       "25         largest_win_pct      87.440000\n",
       "26        largest_win_bars     306.000000\n",
       "27            largest_loss    -834.000000\n",
       "28        largest_loss_pct     -26.650000\n",
       "29       largest_loss_bars      98.000000\n",
       "30                max_wins       9.000000\n",
       "31              max_losses       1.000000\n",
       "32                  sharpe       0.025750\n",
       "33                 sortino       0.036708\n",
       "34           profit_factor       1.075849\n",
       "35             ulcer_index       0.206049\n",
       "36                     upi       0.008957\n",
       "37               equity_r2       0.713317\n",
       "38               std_error     798.998923"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result.metrics_df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th>lower</th>\n",
       "      <th>upper</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>name</th>\n",
       "      <th>conf</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th rowspan=\"3\" valign=\"top\">Profit Factor</th>\n",
       "      <th>97.5%</th>\n",
       "      <td>0.670543</td>\n",
       "      <td>2.097453</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>95%</th>\n",
       "      <td>0.732486</td>\n",
       "      <td>1.907055</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>90%</th>\n",
       "      <td>0.812649</td>\n",
       "      <td>1.699289</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th rowspan=\"3\" valign=\"top\">Sharpe Ratio</th>\n",
       "      <th>97.5%</th>\n",
       "      <td>-0.144344</td>\n",
       "      <td>0.257349</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>95%</th>\n",
       "      <td>-0.112490</td>\n",
       "      <td>0.221865</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>90%</th>\n",
       "      <td>-0.074731</td>\n",
       "      <td>0.185957</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                        lower     upper\n",
       "name          conf                     \n",
       "Profit Factor 97.5%  0.670543  2.097453\n",
       "              95%    0.732486  1.907055\n",
       "              90%    0.812649  1.699289\n",
       "Sharpe Ratio  97.5% -0.144344  0.257349\n",
       "              95%   -0.112490  0.221865\n",
       "              90%   -0.074731  0.185957"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result.bootstrap.conf_intervals"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>amount</th>\n",
       "      <th>percent</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>conf</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>99.9%</th>\n",
       "      <td>-2260.0</td>\n",
       "      <td>-2.205831</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>99%</th>\n",
       "      <td>-1763.0</td>\n",
       "      <td>-1.727226</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>95%</th>\n",
       "      <td>-1378.0</td>\n",
       "      <td>-1.349863</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>90%</th>\n",
       "      <td>-1184.0</td>\n",
       "      <td>-1.162484</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "       amount   percent\n",
       "conf                   \n",
       "99.9% -2260.0 -2.205831\n",
       "99%   -1763.0 -1.727226\n",
       "95%   -1378.0 -1.349863\n",
       "90%   -1184.0 -1.162484"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result.bootstrap.drawdown_conf"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
